package com.blank.server;

import com.blank.model.Quiz;
import com.blank.model.TestReport;
import com.blank.model.User;
import com.blank.model.UserMessage;
import com.blank.util.CommonUtil;
import com.blank.util.ConstEnum;

import java.io.*;
import java.util.LinkedList;
import java.util.Random;

/**
 * 实现服务器的主要功能
 */
public class ServerView {


    private static Random random = new Random();

    /**
     * 使用合成复用原则。
     * 私有化 ServerInitClose 类型的对象引用，从而使用其中的输入输出流。
     * 私有化 ServerDao 类型的对象引用，从而使用其中的数据处理的方法。
     */
    private ServerInitClose sic;
    private ServerDao sd;

    /**
     * 通过构造方法实现成员变量的初始化
     */
    public ServerView(ServerInitClose sic, ServerDao sd) {
        this.sic = sic;
        this.sd = sd;
    }

    /**
     * 接受并处理客户端发来的消息
     */
    public void serverReceive() throws IOException, ClassNotFoundException {
        // 无限循环不断接受处理客户端发来的消息
        while (true) {
            UserMessage userMessage = CommonUtil.cast(sic.getOis().readObject());
            System.out.println("接收到的消息是：" + userMessage);

            switch (userMessage.getType()) {
                // 登录验证功能

                case MANAGER_CHECK:
                    managerCheck(userMessage);
                    break;

                case USER_CHECK:
                    userCheck(userMessage);
                    break;

                 // 管理员系统相关功能

                case ADD_STUDENT:
                    addStudent(userMessage);
                    break;

                case DEL_STUDENT:
                    deleteStudent(userMessage);
                    break;

                case UPD_STUDENT:
                    updateStudent(userMessage);
                    break;

                case GET_STUDENT:
                    searchStudent(userMessage);
                    break;

                case PRINT_ALL_STUDENTS:
                    printAllStudents();
                    break;

                case ADD_QUIZ:
                    addQuiz(userMessage);
                    break;

                case DEL_QUIZ:
                    deleteQuiz(userMessage);
                    break;

                case UPD_QUIZ:
                    updateQuiz(userMessage);
                    break;

                case GET_QUIZ:
                    searchQuiz();
                    break;

                case LOAD_QUIZZES:
                    loadQuizzes(userMessage);
                    break;

                // 学员系统相关功能

                case UPDATE_PASSWORD:
                    updatePassword(userMessage);
                    break;

                case START_TEST:
                    startTest();
                    break;

                case GET_TEST_REPORT:
                    getTestReport();
                    break;

                // 通用功能

                case LOGOUT:
                    sd.clearCurrentUser();
                    break;

                case EXIT:
                    System.out.println("客户端已经下线");
                    return;

                default:
                    System.out.println("未知类型的消息");
            }

            System.out.println("目前用户的信息为：" + sd.getCurrentUser());
            System.out.println();
        }
    }

    /**
     * 实现管理员账户信息的校验功能
     */
    private void managerCheck(UserMessage userMessage) throws IOException {
        // 调用方法实现管理员账户和密码信息的校验
        if (sd.serverManagerCheck(userMessage.getUser())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("校验成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("校验失败");
        }

        // 将校验结果发送给客户端
        System.out.println("服务器发送校验结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现学员账户信息的校验功能
     */
    private void userCheck(UserMessage userMessage) throws IOException {
        // 调用方法实现学员账户和密码信息的校验
        if (sd.serverUserCheck(userMessage.getUser())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("校验成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("校验失败");
        }

        // 将校验结果发送给客户端
        System.out.println("服务器发送校验结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现添加学员的功能
     */
    private void addStudent(UserMessage userMessage) throws IOException {
        // 调用方法实现学员的添加
        if (sd.serverAddStudent(userMessage.getUser())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("添加学员成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("学员信息重复，添加失败");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送添加学员的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现删除学员的功能
     */
    private void deleteStudent(UserMessage userMessage) throws IOException {
        // 调用方法实现学员的删除
        if (sd.serverDelStudent(userMessage.getUser())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("删除学员成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("学员不存在");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送删除学员的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现更新学员的功能
     */
    private void updateStudent(UserMessage userMessage) throws IOException {
        // 调用方法实现学员的更新
        if (sd.serverUpdStudent(userMessage.getUser())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("更新学员成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("学员不存在");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送更新学员的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现查找学员的功能
     */
    private void searchStudent(UserMessage userMessage) throws IOException {
        // 调用方法实现学员的查找
        User user = sd.serverGetStudent(userMessage.getUser());
        if (user != null) {
            userMessage.setType(ConstEnum.SUCCESS);
            userMessage.setUser(user);
            System.out.println("查找学员成功：" + user);
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("学员不存在");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送查找学员的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现遍历所有学员的功能
     */
    private void printAllStudents() throws IOException {
        /*
         * 注意这里要新建一个对象并复制所有学员。
         * 如果直接用 sd.getUserList()，
         * JVM 的性能优化会导致每次获取的都跟第一次获取的一样，无论 UserList 是否有改变。
         */
        LinkedList<User> users = new LinkedList<>(sd.getUserList());

        // 直接发送所有学员的信息到客户端
        System.out.println("服务器发送所有学员的信息");
        sic.getOos().writeObject(users);
    }

    /**
     * 实现增加考题功能
     */
    private void addQuiz(UserMessage userMessage) throws IOException, ClassNotFoundException {
        // 读取客户端发送的考题本身
        Quiz quiz = CommonUtil.cast(sic.getOis().readObject());

        // 调用方法实现考题增加
        if (sd.serverAddQuiz(quiz)) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("增加考题成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("增加考题失败");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送考题增加的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现删除考题功能
     */
    private void deleteQuiz(UserMessage userMessage) throws IOException, ClassNotFoundException {
        // 读取客户端发送的要删除的考题的部分内容
        String keyString = CommonUtil.cast(sic.getOis().readObject());

        // 调用方法实现考题删除
        if (sd.serverDelQuiz(keyString)) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("删除考题成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("考题不存在");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送考题删除的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现修改考题功能
     */
    private void updateQuiz(UserMessage userMessage) throws IOException, ClassNotFoundException {
        // 从客户端读取要修改的考题信息
        String keyString = CommonUtil.cast(sic.getOis().readObject());
        String choices = CommonUtil.cast(sic.getOis().readObject());
        String answer = CommonUtil.cast(sic.getOis().readObject());

        // 调用方法实现考题修改
        if (sd.serverUpdQuiz(keyString, choices, answer)) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("修改考题成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("考题不存在");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送考题修改的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现查找考题功能
     */
    private void searchQuiz() throws IOException, ClassNotFoundException {
        // 从客户端读取要查找的考题信息
        String keyString = CommonUtil.cast(sic.getOis().readObject());

        // 调用方法实现考题的查找，并将结果发送给客户端
        Quiz quiz = sd.serverGetQuiz(keyString);
        if (quiz != null) {
            System.out.println("查找考题成功");
            sic.getOos().writeObject(new Quiz(quiz.getContent(),quiz.getAnswer()));
        } else {
            System.out.println("考题不存在");
            sic.getOos().writeObject(null);
        }
        System.out.println("服务器发送考题查找的结果");
    }

    /**
     * 实现导入考题功能
     */
    private void loadQuizzes(UserMessage userMessage) throws IOException, ClassNotFoundException {
        // 从客户端读取要导入的考题集合
        LinkedList<Quiz> quizzes = CommonUtil.cast(sic.getOis().readObject());

        // 调用方法实现考题导入
        if (sd.serverLoadQuizzes(quizzes)) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("导入考题成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("导入考题失败");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送考题导入的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现修改密码的功能
     */
    private void updatePassword(UserMessage userMessage) throws IOException, ClassNotFoundException {
        // 调用方法实现修改密码
        if (sd.serverUpdPassword(userMessage.getUser().getPassword())) {
            userMessage.setType(ConstEnum.SUCCESS);
            System.out.println("密码修改成功");
        } else {
            userMessage.setType(ConstEnum.FAIL);
            System.out.println("密码修改失败");
        }

        // 将结果发送给客户端
        System.out.println("服务器发送修改密码的结果");
        sic.getOos().writeObject(userMessage);
    }

    /**
     * 实现考试功能
     */
    private void startTest() throws IOException, ClassNotFoundException {
        // 检查题库的数据。
        if (sd.getQuizList() == null || sd.getQuizList().size() < 3) {
            System.out.println("题库没有数据或数据不足，考试无法开始。");
            sic.getOos().writeObject(null);
            return;
        }

        // 随机获取三道考题
        int size = sd.getQuizList().size();
        int i = random.nextInt(size);
        int j = random.nextInt(size);
        int k = random.nextInt(size);
        if (i == j) {
            j = (j + 1) % size;
        }
        if (k == i) {
            k = (k + 1) % size;
        }
        if (k == j) {
            k = (k + 1) % size;
        }
        String[] quizContent = new String[3];
        quizContent[0] = sd.getQuizList().get(i).getContent();
        quizContent[1] = sd.getQuizList().get(j).getContent();
        quizContent[2] = sd.getQuizList().get(k).getContent();

        // 把考题内容发给客户端
        sic.getOos().writeObject(quizContent);

        // 读取客户端返回的考生答案
        String[] studentAnswer = CommonUtil.cast(sic.getOis().readObject());

        // 对比正确答案并得出分数
        int score = 0;
        if (sd.getQuizList().get(i).getAnswer().equalsIgnoreCase(studentAnswer[0])) {
            score++;
        }
        if (sd.getQuizList().get(j).getAnswer().equalsIgnoreCase(studentAnswer[1])) {
            score++;
        }
        if (sd.getQuizList().get(k).getAnswer().equalsIgnoreCase(studentAnswer[2])) {
            score++;
        }

        // 组装成考试成绩报告
        TestReport testReport = new TestReport();
        testReport.setUsername(sd.getCurrentUser().getUsername());
        testReport.setGrade(score);
        Quiz[] quizzes = new Quiz[3];
        testReport.setStudentAnswer(studentAnswer);
        quizzes[0] = sd.getQuizList().get(i);
        quizzes[1] = sd.getQuizList().get(j);
        quizzes[2] = sd.getQuizList().get(k);
        testReport.setQuizList(quizzes);

        System.out.println(testReport);

        // 保存考试成绩报告到数据库
        sd.saveTestReportToDatabase(testReport);
    }

    /**
     * 获取考试成绩功能
     */
    private void getTestReport() throws IOException {
        // 从数据库读取考试成绩报告
        TestReport testReport = sd.getTestReportFromDatabase();
        if (testReport != null) {
            System.out.println("成功获取考试成绩报告");
        } else {
            System.out.println("此学员没有考试成绩报告");
        }
        // 发送考试成绩报告
        sic.getOos().writeObject(testReport);
    }

    /**
     * 导入数据库的数据
     */
    public void loadAllFromDataBase() {
        // 导入数据库的学员账户
        sd. loadUsersFromDatabase();
        // 导入数据库的考题
        sd.loadQuizzesFromDatabase();
    }

    /**
     * 保存数据到数据库
     */
    public void saveAllToDataBase() {
        // 保存考题数据到数据库
        sd.saveQuizzesToDatabase();
        // 保存学员账户数据到数据库
        sd.saveUsersToDataBase();
    }
}
